package org.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Pattern;

/**
 * 哔哩哔哩音频提取器
 * 整合视频解析和音频下载功能
 */
public class BilibiliAudioExtractor {
    private static final Logger logger = LoggerFactory.getLogger(BilibiliAudioExtractor.class);
    
    private final BilibiliParser parser;
    private final AudioDownloader downloader;
    
    public BilibiliAudioExtractor() {
        this.parser = new BilibiliParser();
        this.downloader = new AudioDownloader();
    }
    
    /**
     * 从哔哩哔哩URL提取音频并下载为MP3文件
     * @param bilibiliUrl 哔哩哔哩视频URL
     * @param outputPath 输出目录路径
     * @return 下载的文件路径
     * @throws IOException 处理异常
     */
    public String extractAudioFromUrl(String bilibiliUrl, String outputPath) throws IOException {
        logger.info("开始处理哔哩哔哩URL: {}", bilibiliUrl);
        
        // 1. 提取视频ID
        String videoId = parser.extractVideoId(bilibiliUrl);
        if (videoId == null) {
            throw new IllegalArgumentException("无法从URL中提取视频ID: " + bilibiliUrl);
        }
        
        // 2. 获取视频信息
        BilibiliParser.VideoInfo videoInfo = parser.getVideoInfo(videoId);
        if (videoInfo == null) {
            throw new IOException("无法获取视频信息");
        }
        
        // 3. 获取音频URL
        String audioUrl = parser.getAudioUrl(videoId);
        if (audioUrl == null || audioUrl.trim().isEmpty()) {
            throw new IOException("无法获取音频URL");
        }
        
        // 4. 生成安全的文件名
        String safeFileName = generateSafeFileName(videoInfo.getTitle());
        
        // 5. 下载音频文件
        String downloadedFilePath = downloader.downloadAudio(audioUrl, outputPath, safeFileName);
        
        // 6. 验证下载的文件
        if (!downloader.validateDownloadedFile(downloadedFilePath)) {
            throw new IOException("下载的文件验证失败");
        }
        
        logger.info("音频提取完成: {}", downloadedFilePath);
        return downloadedFilePath;
    }
    
    /**
     * 从哔哩哔哩URL提取音频并下载为MP3文件（使用默认输出目录）
     * @param bilibiliUrl 哔哩哔哩视频URL
     * @return 下载的文件路径
     * @throws IOException 处理异常
     */
    public String extractAudioFromUrl(String bilibiliUrl) throws IOException {
        return extractAudioFromUrl(bilibiliUrl, "downloads");
    }
    
    /**
     * 生成安全的文件名
     * @param title 原始标题
     * @return 安全的文件名
     */
    private String generateSafeFileName(String title) {
        if (title == null || title.trim().isEmpty()) {
            return "bilibili_audio_" + System.currentTimeMillis();
        }
        
        // 移除或替换不安全的字符
        String safeName = title
                .replaceAll("[\\\\/:*?\"<>|]", "_")  // 替换Windows不允许的字符
                .replaceAll("\\s+", "_")             // 替换空格为下划线
                .replaceAll("[^\\w\\s-]", "")        // 移除其他特殊字符
                .trim();
        
        // 限制文件名长度
        if (safeName.length() > 100) {
            safeName = safeName.substring(0, 100);
        }
        
        // 如果文件名为空，使用时间戳
        if (safeName.isEmpty()) {
            safeName = "bilibili_audio_" + System.currentTimeMillis();
        }
        
        return safeName;
    }
    
    /**
     * 验证哔哩哔哩URL格式
     * @param url 要验证的URL
     * @return 是否为有效的哔哩哔哩URL
     */
    public boolean isValidBilibiliUrl(String url) {
        if (url == null || url.trim().isEmpty()) {
            return false;
        }
        
        return parser.extractVideoId(url) != null;
    }
    
    /**
     * 获取视频信息（不下载）
     * @param bilibiliUrl 哔哩哔哩视频URL
     * @return 视频信息
     * @throws IOException 获取信息异常
     */
    public BilibiliParser.VideoInfo getVideoInfo(String bilibiliUrl) throws IOException {
        String videoId = parser.extractVideoId(bilibiliUrl);
        if (videoId == null) {
            throw new IllegalArgumentException("无法从URL中提取视频ID: " + bilibiliUrl);
        }
        
        return parser.getVideoInfo(videoId);
    }
    
    /**
     * 批量处理多个URL
     * @param urls 哔哩哔哩视频URL数组
     * @param outputPath 输出目录路径
     * @return 下载的文件路径数组
     * @throws IOException 处理异常
     */
    public String[] extractAudioFromUrls(String[] urls, String outputPath) throws IOException {
        if (urls == null || urls.length == 0) {
            throw new IllegalArgumentException("URL数组不能为空");
        }
        
        String[] results = new String[urls.length];
        
        for (int i = 0; i < urls.length; i++) {
            try {
                logger.info("处理第 {} 个URL: {}", i + 1, urls[i]);
                results[i] = extractAudioFromUrl(urls[i], outputPath);
                logger.info("第 {} 个URL处理完成", i + 1);
            } catch (Exception e) {
                logger.error("处理第 {} 个URL时发生错误: {}", i + 1, e.getMessage());
                results[i] = null;
            }
        }
        
        return results;
    }
    
    /**
     * 清理下载目录
     * @param directoryPath 目录路径
     */
    public void cleanupDirectory(String directoryPath) {
        try {
            Path directory = Paths.get(directoryPath);
            if (Files.exists(directory)) {
                Files.walk(directory)
                        .sorted((a, b) -> b.compareTo(a)) // 先删除文件，再删除目录
                        .forEach(path -> {
                            try {
                                Files.delete(path);
                                logger.info("已删除: {}", path);
                            } catch (IOException e) {
                                logger.error("删除文件时发生错误: {}", e.getMessage());
                            }
                        });
            }
        } catch (IOException e) {
            logger.error("清理目录时发生错误: {}", e.getMessage());
        }
    }
} 